#include <iostream>
#include <cstdio>
#include <ctime>
#include <sstream>
#include <chrono>
#include <random>
#include <atomic>
#include <iomanip>

// 设置等级 打印不同等级的日志
#define DEBUGLEVEL 0
#define INFOLEVEL 1
#define ERRORLEVEL 2
#define DEFAULTLEVEL INFOLEVEL

// 日志部分
// C语言提供的可变参数模板 
// 这个##__VA_ARGS__ 代表了可变参数的实体
#define LOG(level, format, ...) {\
    if(level >= DEFAULTLEVEL)\
    {\
        time_t t = time(nullptr);\
        struct tm* cur = localtime(&t);\ 
        printf("[%s:%d] " "[%d-%d-%d %d:%d:%d] --> " format "\n", __FILE__, __LINE__, cur->tm_year + 1900, cur->tm_mon + 1, cur->tm_mday\
            , cur->tm_hour, cur->tm_min, cur->tm_sec, ##__VA_ARGS__);\
    }\     
}

std::string UUID()
{
    std::stringstream ss; 
    // 先生成一个机器随机码 这个是唯一的一个值 当作随机数种子 但是机器码产生的随机数比较慢
    std::random_device rd;
    // 生成随机数的函数 导入随机数种子
    std::mt19937 g1(rd());
    // 控制随机数的大小为8字节的数据 这里控制一个16进制的数据为 0-15
    std::uniform_int_distribution<unsigned int> distribution(0, 0xFF);  // 这里定义的是无符号整型类型 所以大小为 0-0xFF
    for(int i = 0; i < 8; i++)
    {
        // 先产生一个字节的数据
        unsigned int num = distribution(g1);
        // std::cout << num << "\n";
        char buffer[1024];
        int n = snprintf(buffer, sizeof(buffer) - 1, "%.2x", num);
        buffer[n] = 0;
        // std::cout << buffer << "\n";
        if(i == 4 || i == 6)
            ss << '-';
        ss << buffer;
    }
    ss << '-';
    // //5. 定义⼀个8字节序号， 也就是8 * 8 = 64 bit位，逐字节组织成为16进制数字字符的字符串 从1开始
    static std::atomic<size_t> seq(1);
    size_t cur = seq.fetch_add(1);  // 代表每次计数 +1 
    for (int i = 7; i >= 0; i--) 
    {
        if (i == 5) ss << "-";
        // 首先设置宽度为 2  不足用 0 补全  然后输出格式是 hex 也就是16进制
        ss << std::setw(2) << std::setfill('0') << std::hex << ((cur >> (i*8)) & 0xFF);  
        //                                              每次拿出一个字节的数据进行按位 & 然后再转化为16进制
    } 
    // std::cout << ss.str() << "\n";
    return ss.str();
}

int main()
{
    for(int i = 0; i < 100; i++)
        std::cout << UUID() << "\n";
    
        return 0;
}

int main1()
{
    // printf("%s\n", "hello world");
    LOG(DEBUGLEVEL, "%s-%d", "hello world", 99);
    return 0;
}